package com.voe;

import com.voe.callback.InStream;
import com.voe.callback.OutStream;
import com.voe.common.CodecInst;
import com.voe.common.FileFormats;
import com.voe.common.OutputParam;
import com.voe.common.ReturnValue;


/**This sub-API supports the following functionalities:<br/>
*<br/>
*- File playback.<br/>
*- File recording.<br/>
*- File conversion.<br/>
*<br/>
*Usage example, omitting error checking:<br/>
*<br/>
*VoiceEngine voe = VoiceEngine.createInterface();<br/>
*VoEBase base = VoEBase.createInterface(voe);<br/>
*VoEFile file  = VoEFile.createInterface(voe);<br/>
*base.init();<br/>
*int ch = base.createChannel();<br/>
*...<br/>
*base.startPlayout(ch);<br/>
*file.startPlayingFileAsMicrophone(ch, "data_file_16kHz.pcm", true);<br/>
*...<br/>
*file.stopPlayingFileAsMicrophone(ch);<br/>
*base.stopPlayout(ch);<br/>
*...<br/>
*base.deleteChannel(ch);<br/>
*base.terminate();<br/>
*base.release();<br/>
*file.release();<br/>
*voe.release();<br/>
*/
public class VoEFile {

	// [start] apis

	public static VoEFile createInstance(VoiceEngine voiceEngine) {

		long p = GetInterface(voiceEngine._p);
		if(p != 0)
			return new VoEFile(p);
		return null;
	}

	public void release() {
		if (_p != 0) {
			Release(_p);
		}
	}

	/** Starts playing and mixing files with the local speaker signal for<br/>
	 *  playout.
	 */
	public int startPlayingFileLocally(int channel, String fileNameUTF8,
			boolean loop, FileFormats format, float volumeScaling,
			int startPointMs, int stopPointMs) {
		return StartPlayingFileLocally(_p, channel, fileNameUTF8, loop,
				format.getValue(), volumeScaling, startPointMs, stopPointMs);
	}

	/** Starts playing and mixing files with the local speaker signal for<br/>
	 *  playout.
	 */
	public int startPlayingFileLocally(int channel, String fileNameUTF8,
			boolean loop, FileFormats format, float volumeScaling,
			int startPointMs) {
		return startPlayingFileLocally(channel, fileNameUTF8, loop,
				format, volumeScaling, startPointMs, 0);
	}

	/** Starts playing and mixing files with the local speaker signal for<br/>
	 *  playout.
	 */
	public int startPlayingFileLocally(int channel, String fileNameUTF8,
			boolean loop, FileFormats format, float volumeScaling) {
		return startPlayingFileLocally(channel, fileNameUTF8, loop,
				format, volumeScaling, 0, 0);
	}

	/** Starts playing and mixing files with the local speaker signal for<br/>
	 *  playout.
	 */
	public int startPlayingFileLocally(int channel, String fileNameUTF8,
			boolean loop, FileFormats format) {
		return startPlayingFileLocally(channel, fileNameUTF8, loop,
				format, 1.0f, 0, 0);
	}

	/** Starts playing and mixing files with the local speaker signal for<br/>
	 *  playout.
	 */
	public int startPlayingFileLocally(int channel, String fileNameUTF8,
			boolean loop) {
		return startPlayingFileLocally(channel, fileNameUTF8, loop,
				FileFormats.kFileFormatPcm16kHzFile, 1.0f, 0, 0);
	}

	/** Starts playing and mixing files with the local speaker signal for<br/>
	 *  playout.
	 */
	public int startPlayingFileLocally(int channel, String fileNameUTF8) {
		return startPlayingFileLocally(channel, fileNameUTF8, false,
				FileFormats.kFileFormatPcm16kHzFile, 1.0f, 0, 0);
	}

	/** Starts playing and mixing streams with the local speaker signal for<br/>
	 *  playout.
	 */
	public int startPlayingFileLocally(int channel, InStream stream,
			FileFormats format, float volumeScaling, int startPointMs,
			int stopPointMs) {
		return StartPlayingFileLocally2(_p, channel, stream, format.getValue(),
				volumeScaling, startPointMs, stopPointMs);
	}

	/** Starts playing and mixing streams with the local speaker signal for<br/>
	 *  playout.
	 */
	public int startPlayingFileLocally(int channel, InStream stream,
			FileFormats format, float volumeScaling, int startPointMs) {
		return startPlayingFileLocally(channel, stream, format,
				volumeScaling, startPointMs, 0);
	}

	/** Starts playing and mixing streams with the local speaker signal for<br/>
	 *  playout.
	 */
	public int startPlayingFileLocally(int channel, InStream stream,
			FileFormats format, float volumeScaling) {
		return startPlayingFileLocally(channel, stream, format,
				volumeScaling, 0, 0);
	}

	/** Starts playing and mixing streams with the local speaker signal for<br/>
	 *  playout.
	 */
	public int startPlayingFileLocally(int channel, InStream stream,
			FileFormats format) {
		return startPlayingFileLocally(channel, stream, format,
				1.0f, 0, 0);
	}

	/** Starts playing and mixing streams with the local speaker signal for<br/>
	 *  playout.
	 */
	public int startPlayingFileLocally(int channel, InStream stream) {
		return startPlayingFileLocally(channel, stream,
				FileFormats.kFileFormatPcm16kHzFile, 1.0f, 0, 0);
	}

	/** Stops playback of a file on a specific |channel|.
	 */
	public int stopPlayingFileLocally(int channel) {
		return StopPlayingFileLocally(_p, channel);
	}

	/** Returns the current file playing state for a specific |channel|.
	 */
	public int isPlayingFileLocally(int channel) {
		return IsPlayingFileLocally(_p, channel);
	}

	/** Sets the volume scaling for a speaker file that is already playing.
	 */
	public int scaleLocalFilePlayout(int channel, float scale) {
		return ScaleLocalFilePlayout(_p, channel, scale);
	}

	/** Starts reading data from a file and transmits the data either<br/>
	 *  mixed with or instead of the microphone signal.
	 */
	public int startPlayingFileAsMicrophone(int channel, String fileNameUTF8,
			boolean loop, boolean mixWithMicrophone, FileFormats format,
			float volumeScaling) {
		return StartPlayingFileAsMicrophone(_p, channel, fileNameUTF8, loop,
				mixWithMicrophone, format.getValue(), volumeScaling);
	}

	/** Starts reading data from a file and transmits the data either<br/>
	 *  mixed with or instead of the microphone signal.
	 */
	public int startPlayingFileAsMicrophone(int channel, String fileNameUTF8,
			boolean loop, boolean mixWithMicrophone, FileFormats format) {
		return startPlayingFileAsMicrophone(channel, fileNameUTF8, loop,
				mixWithMicrophone, format, 0.0f);
	}

	/** Starts reading data from a file and transmits the data either<br/>
	 *  mixed with or instead of the microphone signal.
	 */
	public int startPlayingFileAsMicrophone(int channel, String fileNameUTF8,
			boolean loop, boolean mixWithMicrophone) {
		return startPlayingFileAsMicrophone(channel, fileNameUTF8, loop,
				mixWithMicrophone, FileFormats.kFileFormatPcm16kHzFile, 0.0f);
	}

	/** Starts reading data from a file and transmits the data either<br/>
	 *  mixed with or instead of the microphone signal.
	 */
	public int startPlayingFileAsMicrophone(int channel, String fileNameUTF8,
			boolean loop) {
		return startPlayingFileAsMicrophone(channel, fileNameUTF8, loop,
				false, FileFormats.kFileFormatPcm16kHzFile, 0.0f);
	}

	/** Starts reading data from a file and transmits the data either<br/>
	 *  mixed with or instead of the microphone signal.
	 */
	public int startPlayingFileAsMicrophone(int channel, String fileNameUTF8) {
		return startPlayingFileAsMicrophone(channel, fileNameUTF8, false,
				false, FileFormats.kFileFormatPcm16kHzFile, 0.0f);
	}

	/** Starts reading data from a stream and transmits the data either<br/>
	 *  mixed with or instead of the microphone signal.
	 */
	public int startPlayingFileAsMicrophone(int channel, InStream stream,
			boolean mixWithMicrophone, FileFormats format, float volumeScaling) {
		return StartPlayingFileAsMicrophone2(_p, channel, stream,
				mixWithMicrophone, format.getValue(), volumeScaling);
	}

	/** Starts reading data from a stream and transmits the data either<br/>
	 *  mixed with or instead of the microphone signal.
	 */
	public int startPlayingFileAsMicrophone(int channel, InStream stream,
			boolean mixWithMicrophone, FileFormats format) {
		return startPlayingFileAsMicrophone(channel, stream,
				mixWithMicrophone, format, 0.0f);
	}

	/** Starts reading data from a stream and transmits the data either<br/>
	 *  mixed with or instead of the microphone signal.
	 */
	public int startPlayingFileAsMicrophone(int channel, InStream stream,
			boolean mixWithMicrophone) {
		return startPlayingFileAsMicrophone(channel, stream,
				mixWithMicrophone, FileFormats.kFileFormatPcm16kHzFile, 0.0f);
	}

	/** Starts reading data from a stream and transmits the data either<br/>
	 *  mixed with or instead of the microphone signal.
	 */
	public int startPlayingFileAsMicrophone(int channel, InStream stream) {
		return startPlayingFileAsMicrophone(channel, stream,
				false, FileFormats.kFileFormatPcm16kHzFile, 0.0f);
	}

	/** Stops playing of a file as microphone signal for a specific |channel|.
	 */
	public int stopPlayingFileAsMicrophone(int channel) {
		return StopPlayingFileAsMicrophone(_p, channel);
	}

	/** Returns whether the |channel| is currently playing a file as microphone.
	 */
	public int isPlayingFileAsMicrophone(int channel) {
		return IsPlayingFileAsMicrophone(_p, channel);
	}

	/** Sets the volume scaling for a microphone file that is already playing.
	 */
	public int scaleFileAsMicrophonePlayout(int channel, float scale) {
		return ScaleFileAsMicrophonePlayout(_p, channel, scale);
	}

	/** Starts recording the mixed playout audio.
	 */
	public int startRecordingPlayout(int channel, String fileNameUTF8,
			CodecInst compression, int maxSizeBytes) {
		return StartRecordingPlayout(_p, channel, fileNameUTF8, compression,
				maxSizeBytes);
	}

	/** Starts recording the mixed playout audio.
	 */
	public int startRecordingPlayout(int channel, String fileNameUTF8,
			CodecInst compression) {
		return startRecordingPlayout(channel, fileNameUTF8, compression,
				-1);
	}

	/** Starts recording the mixed playout audio.
	 */
	public int startRecordingPlayout(int channel, String fileNameUTF8) {
		return startRecordingPlayout(channel, fileNameUTF8, null, -1);
	}

	/** Stops recording the mixed playout audio.
	 */
	public int stopRecordingPlayout(int channel) {
		return StopRecordingPlayout(_p, channel);
	}

	public int startRecordingPlayout(int channel, OutStream stream,
			CodecInst compression) {
		return StartRecordingPlayout2(_p, channel, stream, compression);
	}

	public int startRecordingPlayout(int channel, OutStream stream) {
		return startRecordingPlayout(channel, stream, null);
	}

	/** Starts recording the microphone signal to a file.
	 */
	public int startRecordingMicrophone(String fileNameUTF8,
			CodecInst compression, int maxSizeBytes) {
		return StartRecordingMicrophone(_p, fileNameUTF8, compression,
				maxSizeBytes);
	}

	/** Starts recording the microphone signal to a file.
	 */
	public int startRecordingMicrophone(String fileNameUTF8,
			CodecInst compression) {
		return startRecordingMicrophone(fileNameUTF8, compression, -1);
	}

	/** Starts recording the microphone signal to a file.
	 */
	public int startRecordingMicrophone(String fileNameUTF8) {
		return startRecordingMicrophone(fileNameUTF8, null, -1);
	}

	/** Starts recording the microphone signal to a stream.
	 */
	public int startRecordingMicrophone(OutStream stream, CodecInst compression) {
		return StartRecordingMicrophone2(_p, stream, compression);
	}

	/** Starts recording the microphone signal to a stream.
	 */
	public int startRecordingMicrophone(OutStream stream) {
		return startRecordingMicrophone(stream, null);
	}

	/** Stops recording the microphone signal.
	 */
	public int stopRecordingMicrophone() {
		return StopRecordingMicrophone(_p);
	}

	/** Gets the duration of a file.
	 */
	public int getFileDuration(String fileNameUTF8, ReturnValue<Integer> durationMs,
			FileFormats format) {
		OutputParam output = new OutputParam();
		int result = GetFileDuration(_p, fileNameUTF8, output, format.getValue());
		if(result == 0) {
			durationMs.setValue((Integer)output.getObject()[0]);
		}
		return result;
	}

	/** Gets the duration of a file.
	 */
	public int getFileDuration(String fileNameUTF8, ReturnValue<Integer> durationMs) {
		return getFileDuration(fileNameUTF8, durationMs, FileFormats.kFileFormatPcm16kHzFile);
	}

	/** Gets the current played position of a file on a specific |channel|.
	 */
	public int getPlaybackPosition(int channel,
			ReturnValue<Integer> positionMs) {
		OutputParam output = new OutputParam();
		int result = GetPlaybackPosition(_p, channel, output);
		if(result == 0) {
			positionMs.setValue((Integer) output.getObject()[0]);
		}
		return result;
	}

	public int convertPCMToWAV(String fileNameInUTF8, String fileNameOutUTF8) {
		return ConvertPCMToWAV(_p, fileNameInUTF8, fileNameOutUTF8);
	}

	public int convertPCMToWAV(InStream streamIn, OutStream streamOut) {
		return ConvertPCMToWAV2(_p, streamIn, streamOut);
	}

	public int convertWAVToPCM(String fileNameInUTF8, String fileNameOutUTF8) {
		return ConvertWAVToPCM(_p, fileNameInUTF8, fileNameOutUTF8);
	}

	public int convertWAVToPCM(InStream streamIn, OutStream streamOut) {
		return ConvertWAVToPCM2(_p, streamIn, streamOut);
	}

	public int convertPCMToCompressed(String fileNameInUTF8,
			String fileNameOutUTF8, CodecInst compression) {
		return ConvertPCMToCompressed(_p, fileNameInUTF8, fileNameOutUTF8,
				compression);
	}

	public int convertPCMToCompressed(InStream streamIn, OutStream streamOut,
			CodecInst compression) {
		return ConvertPCMToCompressed2(_p, streamIn, streamOut, compression);
	}

	public int convertCompressedToPCM(String fileNameInUTF8,
			String fileNameOutUTF8) {
		return ConvertCompressedToPCM(_p, fileNameInUTF8, fileNameOutUTF8);
	}

	public int convertCompressedToPCM(InStream streamIn, OutStream streamOut) {
		return ConvertCompressedToPCM2(_p, streamIn, streamOut);
	}

	protected VoEFile(long p) {
		_p = p;
	}

	protected long _p;

	// [end]

	// [start] jni api

	// Factory for the VoEFile sub-API. Increases an internal
	// reference counter if successful. Returns NULL if the API is not
	// supported or if construction fails.
	private static native long GetInterface(long p_voiceEngine);

	// Releases the VoEFile sub-API and decreases an internal
	// reference counter. Returns the new reference count. This value should
	// be zero for all sub-API:s before the VoiceEngine object can be safely
	// deleted.
	private static native int Release(long p_VoEFile);

	// Starts playing and mixing files with the local speaker signal for
	// playout.
	private static native int StartPlayingFileLocally(long p_VoEFile,
			int channel, String fileNameUTF8, boolean loop, int format,
			float volumeScaling, int startPointMs, int stopPointMs);

	// Starts playing and mixing streams with the local speaker signal for
	// playout.
	private static native int StartPlayingFileLocally2(long p_VoEFile,
			int channel, InStream stream, int format, float volumeScaling,
			int startPointMs, int stopPointMs);

	// Stops playback of a file on a specific |channel|.
	private static native int StopPlayingFileLocally(long p_VoEFile, int channel);

	// Returns the current file playing state for a specific |channel|.
	private static native int IsPlayingFileLocally(long p_VoEFile, int channel);

	// Sets the volume scaling for a speaker file that is already playing.
	private static native int ScaleLocalFilePlayout(long p_VoEFile,
			int channel, float scale);

	// Starts reading data from a file and transmits the data either
	// mixed with or instead of the microphone signal.
	private static native int StartPlayingFileAsMicrophone(long p_VoEFile,
			int channel, String fileNameUTF8, boolean loop,
			boolean mixWithMicrophone, int format, float volumeScaling);

	// Starts reading data from a stream and transmits the data either
	// mixed with or instead of the microphone signal.
	private static native int StartPlayingFileAsMicrophone2(long p_VoEFile,
			int channel, InStream stream, boolean mixWithMicrophone,
			int format, float volumeScaling);

	// Stops playing of a file as microphone signal for a specific |channel|.
	private static native int StopPlayingFileAsMicrophone(long p_VoEFile,
			int channel);

	// Returns whether the |channel| is currently playing a file as microphone.
	private static native int IsPlayingFileAsMicrophone(long p_VoEFile,
			int channel);

	// Sets the volume scaling for a microphone file that is already playing.
	private static native int ScaleFileAsMicrophonePlayout(long p_VoEFile,
			int channel, float scale);

	// Starts recording the mixed playout audio.
	private static native int StartRecordingPlayout(long p_VoEFile,
			int channel, String fileNameUTF8, CodecInst compression,
			int maxSizeBytes);

	// Stops recording the mixed playout audio.
	private static native int StopRecordingPlayout(long p_VoEFile, int channel);

	private static native int StartRecordingPlayout2(long p_VoEFile,
			int channel, OutStream stream, CodecInst compression);

	// Starts recording the microphone signal to a file.
	private static native int StartRecordingMicrophone(long p_VoEFile,
			String fileNameUTF8, CodecInst compression, int maxSizeBytes);

	// Starts recording the microphone signal to a stream.
	private static native int StartRecordingMicrophone2(long p_VoEFile,
			OutStream stream, CodecInst compression);

	// Stops recording the microphone signal.
	private static native int StopRecordingMicrophone(long p_VoEFile);

	// Gets the duration of a file.
	private static native int GetFileDuration(long p_VoEFile,
			String fileNameUTF8, OutputParam durationMs, int format);

	// Gets the current played position of a file on a specific |channel|.
	private static native int GetPlaybackPosition(long p_VoEFile, int channel,
			OutputParam positionMs);

	private static native int ConvertPCMToWAV(long p_VoEFile,
			String fileNameInUTF8, String fileNameOutUTF8);

	private static native int ConvertPCMToWAV2(long p_VoEFile,
			InStream streamIn, OutStream streamOut);

	private static native int ConvertWAVToPCM(long p_VoEFile,
			String fileNameInUTF8, String fileNameOutUTF8);

	private static native int ConvertWAVToPCM2(long p_VoEFile,
			InStream streamIn, OutStream streamOut);

	private static native int ConvertPCMToCompressed(long p_VoEFile,
			String fileNameInUTF8, String fileNameOutUTF8, CodecInst compression);

	private static native int ConvertPCMToCompressed2(long p_VoEFile,
			InStream streamIn, OutStream streamOut, CodecInst compression);

	private static native int ConvertCompressedToPCM(long p_VoEFile,
			String fileNameInUTF8, String fileNameOutUTF8);

	private static native int ConvertCompressedToPCM2(long p_VoEFile,
			InStream streamIn, OutStream streamOut);

	// [end]
}
